package cn.iocoder.yudao.framework.business.basic.dao.repository;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;

import java.time.Duration;
import java.time.LocalDateTime;

/**
 * 序列号的 Redis DAO
 *
 * @author 芋道源码
 */
@Repository
public class SerialNoRedisRepository {
    /**
     * 用户推荐码的缓存
     * KEY 格式：xianmin:universal:member_no:{prefix}
     * VALUE 数据格式：编号自增
     */
    private static final String MEMBER_NO = "xianmin:universal:member_no:";
    /**
     * 交易单号的缓存
     * KEY 格式：xianmin:universal:trade_no:{prefix}
     * VALUE 数据格式：编号自增
     */
    private static final String TRADE_NO = "xianmin:universal:trade_no:";

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 用户推荐码，需确保长度为10，格式：{random}{serial}
     *
     * @return 序号
     */
    public String generateMemberNo() {
        String noPrefix = RandomUtil.randomNumbers(8);
        String key = MEMBER_NO + noPrefix;
        Long serial = stringRedisTemplate.opsForValue().increment(key);
        if (serial == null) {
            serial = 0L;
        }
        // 设置过期时间，暂定1秒内支持最多99人并发注册
        stringRedisTemplate.expire(key, Duration.ofSeconds(1L));
        return noPrefix + StrUtil.padPre(String.valueOf(serial), 2, '0');
    }

    /**
     * 交易单号，格式：{prefix}{yyyyMMddHHmmss}{serial+random}
     *
     * @param prefix 前缀
     * @return 序号
     */
    public String generateNo(String prefix) {
        // 递增序号
        String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
        String key = TRADE_NO + noPrefix;
        Long serial = stringRedisTemplate.opsForValue().increment(key);
        if (serial == null) {
            serial = 0L;
        }
        serial += RandomUtil.randomLong(1000, 9999);
        // 设置过期时间
        stringRedisTemplate.expire(key, Duration.ofMinutes(1L));
        return noPrefix + serial;
    }

}
